package utstat.listeners;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import utstat.Balancx0r;
import utstat.Rcon;
import utstat.SpawnManager;
import utstat.Swap;
import utstat.Team;
import utstat.Type;
import utstat.UtEvent;
import utstat.UtEventListener;
/**
 * killed by 3 or more people
 */
public class BalanceListener implements UtEventListener {

	private int currentRound = -1;
	private final int defaultScore = 15;
	private Balancx0r balanancX0r = new Balancx0r();
	private Map<String,Player> players = new HashMap<String,Player>(); // persistent
	private List<UtEvent> gameplayEvents = new ArrayList<UtEvent>();
	private final float recentScoreWeight = 0.4f;
	private int captureActivityScore = 5;
	private int dropActivityScore = 1;
	private int returnActivityScore = 1;
	private int grabActivityScore = 2;
	private int spawnOffset = 0;
	private int activityPointsPerSpawnPenalty = 10;
	private int previousSpawnOffset =0;
	private Swap bestSwap;
	private Integer teamSpawnOffset;
	private Integer teamBalance;

	@Override
	public String getIntestingFact(String player) {
		return null;
	}

	@Override
	public void processEvent(UtEvent e) {

		if (e.getRound() != currentRound) {
			nextRound();
			currentRound = e.getRound();
		}

		
		
		switch(e.getType()) {

		case teamChange: 
			if (e.getSrc() == null) return;
			String playerName = e.getSrc();
			if(!players.containsKey(playerName)) {
				Player newPlayer = new Player(playerName, e.getTeam(), defaultScore);
				players.put(playerName, newPlayer);
			}
			Player player = players.get(playerName);
			player.currentTeam = e.getTeam();
			
		//	System.out.println("=====================");
			//System.out.println(e.getSrc()+" moved to "+e.getTeam());
			for(Team t : Team.values()) {
				if(t!=Team.red&&t!=Team.blue)continue; 
				List<Player> team = getTeamMembers(t);
				if(team.size()==0) continue;
			//	System.out.println("=== "+t+" ===");
				for(Player p : team) {
			//		System.out.println(p);
				}	
			}
			Collection<Player> allPlayers = players.values();

			Map<String,Object> balanceResult = balanancX0r.balance(allPlayers);
			if(balanceResult==null) return;
			bestSwap = (Swap)balanceResult.get("swap");
			teamSpawnOffset = (Integer)balanceResult.get("redTimeOffset");
			teamBalance = (Integer)balanceResult.get("balance");
			
			break;
			
		case command: 
			System.out.println(e.getMessage());
			if(e.getMessage().equals("balance")) {
				System.out.println("balance2");
				Rcon.say("teams are "+teamBalance+" percent balanced");
			}
			if(e.getMessage().equals("balance suggest")) {
				Rcon.say(bestSwap.toString());
			}
			if(e.getMessage().equals("balance now")) {
				SpawnManager.setTeamBalanceSpawnOffset(teamSpawnOffset);
				Rcon.executeSwap(bestSwap);
			}
			break;
		
		case score:
			if (e.getSrc() == null) return;
			int s = players.get(e.getSrc()).score;
			s *= (1 - recentScoreWeight);
			s += +(e.getScore() * recentScoreWeight);
			players.get(e.getSrc()).score = s;
		break;
		
		case flagCapture:
		case flagDrop:
		case flagReturn:
		case flagGrab:
			gameplayEvents.add(e);
			int gameplayBalance = getGameplayBalance();

				spawnOffset = gameplayBalance/activityPointsPerSpawnPenalty;
				if(spawnOffset!=previousSpawnOffset)
					SpawnManager.setGameBalanceSpawnOffset(spawnOffset);
				previousSpawnOffset = spawnOffset;


			break;
		
		}
	}



	private int getGameplayBalance() {
		int blueFlagActivity =1;
		int redFlagActivity = 1;
		for(UtEvent event : gameplayEvents) {
			boolean isBlue = event.getTeam()==Team.blue;
			switch (event.getType()) {
			default: continue;
			case flagCapture: if(isBlue) redFlagActivity+=captureActivityScore; else blueFlagActivity+=captureActivityScore;break;
			case flagDrop:    if(isBlue) blueFlagActivity+=dropActivityScore;    else redFlagActivity+=dropActivityScore;break;
			case flagReturn:  if(isBlue) blueFlagActivity+=returnActivityScore;  else redFlagActivity+=returnActivityScore;break;
			case flagGrab:	  if(isBlue) blueFlagActivity+=grabActivityScore;    else redFlagActivity+=grabActivityScore;break;
			}
		}

		int balance = redFlagActivity- blueFlagActivity;
		return balance;
	}

	private List<Player> getTeamMembers(Team t) {
		List<Player> team = new ArrayList<Player>();
		for(Player p : players.values()) 
			if(p.currentTeam == t) team.add(p);			
		return team;
	}


	private void nextRound() {
		System.out.println("---------");
		for(Player p : players.values()) 
			p.currentTeam = Team.disconnected;
		gameplayEvents = new ArrayList<UtEvent>();
		spawnOffset=0;
		SpawnManager.nextRound();
	}

public class Event {
	public Event(Type type,int time) {this.time=time;this.eventType=type;}
	public Type eventType;
	public int time;
}
}